package cn.skynethome.redisx.spring;

import java.util.Collection;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;

import org.apache.commons.lang.StringUtils;
import org.apache.log4j.Logger;

import cn.skynethome.redisx.FileUtil;
import cn.skynethome.redisx.SerializationAndCompressUtils;
import cn.skynethome.redisx.common.ms.MasterSlaveJedis;
import cn.skynethome.redisx.common.ms.MasterSlaveJedisSentinelPool;
import cn.skynethome.redisx.common.ms.ShardedMasterSlaveJedis;
import redis.clients.jedis.JedisPoolConfig;
import redis.clients.util.Pool;

/**
  * 项目名称:[redisx]
  * 包:[cn.skynethome.redisx.spring]    
  * 文件名称:[RedisXSentinel]  
  * 描述:[一句话描述该文件的作用]
  * 创建人:[陆文斌]
  * 创建时间:[2017年1月4日 下午2:47:47]   
  * 修改人:[陆文斌]   
  * 修改时间:[2017年1月4日 下午2:47:47]   
  * 修改备注:[说明本次修改内容]  
  * 版权所有:luwenbin006@163.com
  * 版本:[v1.0]
 */
public class RedisXSentinel {
	
	protected  Logger logger = Logger.getLogger(RedisXSentinel.class);

    // redis_sentinel服务器IP
    private  String ADDR_ARRAY = null; // 192.168.0.1:63781,192.168.0.1:63782

    private  String MASTER_NAME = null; // master1,master2

    // redis_sentinel的端口号
    // private  int PORT =
    // FileUtil.getPropertyValueInt("properties/redis_sentinel.properties",
    // "port");

    // 访问密码
    private  String AUTH = null;

    // 可用连接实例的最大数目，默认值为8；
    // 如果赋值为-1，则表示不限制；如果pool已经分配了maxActive个jedis实例，则此时pool的状态为exhausted(耗尽)。
    private  int MAX_ACTIVE = 0;

    // 控制一个pool最多有多少个状态为idle(空闲的)的jedis实例，默认值也是8。
    private  int MAX_IDLE = 0;

    // 等待可用连接的最大时间，单位毫秒，默认值为-1，表示永不超时。如果超过等待时间，则直接抛出JedisConnectionException；
    private  int MAX_WAIT = 0;

    // 超时时间
    private  int TIMEOUT = 0;

    // 在borrow一个jedis实例时，是否提前进行validate操作；如果为true，则得到的jedis实例均是可用的；
    private  boolean TEST_ON_BORROW = false;

    private  Pool<MasterSlaveJedis> masterSlaveJedisPool = null;

    private boolean configFlag = false;
    
    private  String configPath="properties/redis_sentinel.properties";

    
    public String getADDR_ARRAY() {
		return ADDR_ARRAY;
	}

	public void setADDR_ARRAY(String aDDR_ARRAY) {
		ADDR_ARRAY = aDDR_ARRAY;
	}

	public String getMASTER_NAME() {
		return MASTER_NAME;
	}

	public void setMASTER_NAME(String mASTER_NAME) {
		MASTER_NAME = mASTER_NAME;
	}

	public String getAUTH() {
		return AUTH;
	}

	public void setAUTH(String aUTH) {
		AUTH = aUTH;
	}

	public int getMAX_ACTIVE() {
		return MAX_ACTIVE;
	}

	public void setMAX_ACTIVE(int mAX_ACTIVE) {
		MAX_ACTIVE = mAX_ACTIVE;
	}

	public int getMAX_IDLE() {
		return MAX_IDLE;
	}

	public void setMAX_IDLE(int mAX_IDLE) {
		MAX_IDLE = mAX_IDLE;
	}

	public int getMAX_WAIT() {
		return MAX_WAIT;
	}

	public void setMAX_WAIT(int mAX_WAIT) {
		MAX_WAIT = mAX_WAIT;
	}

	public int getTIMEOUT() {
		return TIMEOUT;
	}

	public void setTIMEOUT(int tIMEOUT) {
		TIMEOUT = tIMEOUT;
	}

	public boolean isTEST_ON_BORROW() {
		return TEST_ON_BORROW;
	}

	public void setTEST_ON_BORROW(boolean tEST_ON_BORROW) {
		TEST_ON_BORROW = tEST_ON_BORROW;
	}

	public boolean isConfigFlag() {
		return configFlag;
	}

	public void setConfigFlag(boolean configFlag) {
		this.configFlag = configFlag;
	}

	public String getConfigPath() {
		return configPath;
	}

	public void setConfigPath(String configPath) {
		this.configPath = configPath;
	}

	/**
     * 初始化Redis连接池
     */
    private  void initialPool()
    {

        initRedisConfigValue();
        JedisPoolConfig config = new JedisPoolConfig();
        config.setMaxTotal(MAX_ACTIVE);
        config.setMaxIdle(MAX_IDLE);
        config.setMaxWaitMillis(MAX_WAIT);
        config.setTestOnBorrow(TEST_ON_BORROW);

        Set<String> sentinels = new LinkedHashSet<String>();
        if (!StringUtils.isEmpty(ADDR_ARRAY))
        {
            String[] address = ADDR_ARRAY.split(",");
            for (String add : address)
            {
                sentinels.add(add);
            }
        }

        masterSlaveJedisPool = new MasterSlaveJedisSentinelPool(MASTER_NAME, sentinels, config, TIMEOUT,AUTH);
    }

    private  void initRedisConfigValue()
    {
        // TODO Auto-generated method stub
        if(configFlag)
        {
	    	ADDR_ARRAY = FileUtil.getPropertyValue(configPath, "server"); // 192.168.0.1:63781,192.168.0.1:63782
	
	        MASTER_NAME = FileUtil.getPropertyValue(configPath, "master_name"); // master1,master2
	
	        AUTH = FileUtil.getPropertyValue(configPath, "auth");
	        MAX_ACTIVE = FileUtil.getPropertyValueInt(configPath, "max_active");
	
	        MAX_IDLE = FileUtil.getPropertyValueInt(configPath, "max_idle");
	
	        MAX_WAIT = FileUtil.getPropertyValueInt(configPath, "max_wait");
	
	        TIMEOUT = FileUtil.getPropertyValueInt(configPath, "timeout");
	
	        TEST_ON_BORROW = FileUtil.getPropertyValueBoolean(configPath, "test_on_borrow");
	
	        FileUtil.remove(configPath);
        
        }
    }

    /**
     * 在多线程环境同步初始化
     */
    private  synchronized void poolInit()
    {
        if (masterSlaveJedisPool == null)
        {
            initialPool();
        }
    }

    /**
     * 同步获取Jedis实例
     * 
     * @return Jedis
     */
    public synchronized  MasterSlaveJedis getJedis()
    {
        if (masterSlaveJedisPool == null)
        {
            poolInit();
        }
        MasterSlaveJedis jedis = null;
        try
        {
            if (masterSlaveJedisPool != null)
            {
                jedis = masterSlaveJedisPool.getResource();
            }
        }
        catch (Exception e)
        {
            returnResource(jedis);
            logger.error("Get jedis error : " + e);
        }

        return jedis;
    }

    // /**
    // * slave jedis
    // * @return
    // */
    // public synchronized  Jedis getSlaveJedis()
    // {
    // if (masterSlaveJedisPool == null)
    // {
    // poolInit();
    // }
    // MasterSlaveJedis masterSlaveJedis = null;
    // Jedis jedis = null;
    // try
    // {
    // if (masterSlaveJedisPool != null)
    // {
    // masterSlaveJedis = masterSlaveJedisPool.getResource();
    // jedis = masterSlaveJedis.opsForSlave();
    // }
    // }
    // catch (Exception e)
    // {
    // logger.error("Get jedis error : " + e);
    // }
    //
    // return jedis;
    // }

    /**
     * 释放jedis资源
     * 
     * @param jedis
     */
    public  void returnResource(final MasterSlaveJedis jedis)
    {
        if (jedis != null)
        {
            jedis.close();
            // jedis.close();
        }
    }

    /**
     * 设置 String
     * 
     * @param key
     * @param value
     */
    public  String setString(String key, String value)
    {
        MasterSlaveJedis masterSlaveJedis = null;
        String r_str = "nil";
        try
        {
            value = StringUtils.isEmpty(value) ? "" : value;
            masterSlaveJedis = getJedis();
            r_str = masterSlaveJedis.set(key, value);
        }
        catch (Exception e)
        {
            returnResource(masterSlaveJedis);
            masterSlaveJedis=null;
            logger.error("Set key error : " + e);
        }
        finally
        {
            returnResource(masterSlaveJedis);
        }
        
        return r_str;
    }

    /**
     * 设置 过期时间
     * 
     * @param key
     * @param seconds
     *            以秒为单位
     * @param value
     */
    public  String setString(String key, String value, int expirationTime)
    {
        MasterSlaveJedis masterSlaveJedis = null;
        String r_str = "nil";
        try
        {
            value = StringUtils.isEmpty(value) ? "" : value;
            masterSlaveJedis = getJedis();
            r_str = masterSlaveJedis.setex(key, expirationTime, value);
        }
        catch (Exception e)
        {
            returnResource(masterSlaveJedis);
            masterSlaveJedis = null;
            logger.error("Set keyex error : " + e);
        }
        finally
        {
            returnResource(masterSlaveJedis);
        }
        
        return r_str;
    }

    public  Set<byte[]> getKeys(byte[] keys)
    {
        MasterSlaveJedis masterSlaveJedis = getJedis();
        Set<byte[]> set_ = masterSlaveJedis.opsForSlave().keys(keys);
        returnResource(masterSlaveJedis);
        return set_;

    }

    public  Set<String> getKeys(String keys)
    {
        MasterSlaveJedis masterSlaveJedis = getJedis();
        Set<String> set_ = masterSlaveJedis.opsForSlave().keys(keys);
        returnResource(masterSlaveJedis);
        return set_;

    }

    public  Set<byte[]> hkeys(byte[] hkeys)
    {
        MasterSlaveJedis masterSlaveJedis = getJedis();
        Set<byte[]> set_ = masterSlaveJedis.opsForSlave().hkeys(hkeys);
        returnResource(masterSlaveJedis);
        return set_;
    }

    public  Set<String> hkeys(String hkeys)
    {
        MasterSlaveJedis masterSlaveJedis = getJedis();
        Set<String> set_ = masterSlaveJedis.opsForSlave().hkeys(hkeys);
        returnResource(masterSlaveJedis);
        return set_;
    }

    public  Collection<byte[]> hvals(byte[] hvals)
    {
        MasterSlaveJedis masterSlaveJedis = getJedis();
        Collection<byte[]> collection = masterSlaveJedis.opsForSlave().hvals(hvals);
        returnResource(masterSlaveJedis);
        return collection;
    }

    public  List<String> hvals(String hvals)
    {
        MasterSlaveJedis masterSlaveJedis = getJedis();
        List<String> list = masterSlaveJedis.opsForSlave().hvals(hvals);
        returnResource(masterSlaveJedis);
        return list;
    }

    /**
     * 获取String值
     * 
     * @param key
     * @return value
     */
    public  String getString(String key)
    {
        MasterSlaveJedis masterSlaveJedis = getJedis();
        String r_str = null;
        if (masterSlaveJedis == null || !masterSlaveJedis.exists(key))
        {
            r_str = null;
            returnResource(masterSlaveJedis);
        }else
        {
            r_str = masterSlaveJedis.get(key);
            returnResource(masterSlaveJedis);
        }

        return r_str;
    }

    public  String setObject(String key, Object obj, int expirationTime)
    {
        String r_t = "nil";
        MasterSlaveJedis masterSlaveJedis = getJedis();
        try
        {

            r_t = masterSlaveJedis.setex(key.getBytes(), expirationTime, SerializationAndCompressUtils.fastSerialize(obj));

        }
        catch (Exception e)
        {
            // TODO Auto-generated catch block
           returnResource(masterSlaveJedis);
           masterSlaveJedis = null;
            e.printStackTrace();
        }
        finally
        {
            
                returnResource(masterSlaveJedis);
            
        }
        return r_t;

    }

    public  String setObject(String key, Object obj)
    {
        String r_t = "nil";
        MasterSlaveJedis masterSlaveJedis = getJedis();
        try
        {
            r_t = masterSlaveJedis.set(key.getBytes(), SerializationAndCompressUtils.fastSerialize(obj));

        }
        catch (Exception e)
        {
            returnResource(masterSlaveJedis);
            masterSlaveJedis = null;
            e.printStackTrace();
        }
        finally
        {
            
                returnResource(masterSlaveJedis);
            
        }
        return r_t;

    }

    public  Long del(String key)
    {
        Long d_l = 0l;
        MasterSlaveJedis masterSlaveJedis = getJedis();
        try
        {

            d_l = masterSlaveJedis.del(key);

        }
        catch (Exception e)
        {
            returnResource(masterSlaveJedis);
            masterSlaveJedis = null;
            e.printStackTrace();
        }
        finally
        {
                returnResource(masterSlaveJedis);
        }
        return d_l;

    }

    public  Long del(byte[] key)
    {
        Long d_l = 0l;
        MasterSlaveJedis masterSlaveJedis = getJedis();
        try
        {

            d_l = masterSlaveJedis.del(key);

        }
        catch (Exception e)
        {
            returnResource(masterSlaveJedis);
            masterSlaveJedis = null;
            e.printStackTrace();
        }
        finally
        {
                returnResource(masterSlaveJedis);
        }
        return d_l;

    }

    public  Long del(byte[]... key)
    {
        Long d_l = 0l;
        MasterSlaveJedis masterSlaveJedis = getJedis();
        try
        {
            d_l = masterSlaveJedis.del(key);
        }
        catch (Exception e)
        {
            returnResource(masterSlaveJedis);
            masterSlaveJedis = null;
            e.printStackTrace();
        }
        finally
        {
                returnResource(masterSlaveJedis);
        }
        return d_l;

    }

    /**
     * 获取Object
     * 
     * @param key
     * @return
     * @return value
     */
    public  <T> T getObject(String key, Class<T> classz)
    {
        MasterSlaveJedis masterSlaveJedis = getJedis();
        T t = null;
        if (masterSlaveJedis == null || !masterSlaveJedis.exists(key))
        {
            t = null;
            returnResource(masterSlaveJedis);
        }else
        {
            byte[] value = masterSlaveJedis.opsForSlave().get(key.getBytes());

            try
            {

                t = classz.cast(SerializationAndCompressUtils.fastDeserialize(value));

            }
            catch (Exception e)
            {
                returnResource(masterSlaveJedis);
                masterSlaveJedis = null;
                e.printStackTrace();
            }
            finally
            {
                    returnResource(masterSlaveJedis);
            }
        }

        

        return t;
    }

    public  Long hdel(String key, String field)
    {
        Long r_l = 0l;
        MasterSlaveJedis masterSlaveJedis = getJedis();
        if (masterSlaveJedis == null)
        {
            r_l = 0l;
        }else
        {
            try
            {

                r_l = masterSlaveJedis.hdel(key, field);
            }
            catch (Exception e)
            {
                returnResource(masterSlaveJedis);
                masterSlaveJedis = null;
                e.printStackTrace();
            }
            finally
            {
                    returnResource(masterSlaveJedis);
            }
        }

       
        return r_l;
    }

    public  Map<String, String> hgetall(String key)
    {
        MasterSlaveJedis masterSlaveJedis = getJedis();
        Map<String, String> map = null;
        if (masterSlaveJedis == null)
        {
            return null;
        }else
        {
            try
            {
                map =  masterSlaveJedis.opsForSlave().hgetAll(key);

            }
            catch (Exception e)
            {
                returnResource(masterSlaveJedis);
                masterSlaveJedis = null;
                e.printStackTrace();
            }
            finally
            {
                    returnResource(masterSlaveJedis);
            }
        }

        
        return map;
    }

    public  Long hincrBy(String key, String field, long value)
    {
        MasterSlaveJedis masterSlaveJedis = getJedis();
        Long r_l = 0l;
        if (masterSlaveJedis == null)
        {
            r_l = 0l;
        }else
        {
            try
            {
                r_l = masterSlaveJedis.hincrBy(key, field, value);
            }
            catch (Exception e)
            {
                returnResource(masterSlaveJedis);
                masterSlaveJedis = null;
                e.printStackTrace();
            }
            finally
            {
                    returnResource(masterSlaveJedis);
            }
        }

       
        return r_l;
    }
    
    public boolean exists(byte[] key)
    {
        MasterSlaveJedis masterSlaveJedis = getJedis();
        boolean isExists = false;
        
        if (masterSlaveJedis == null)
        {
            isExists = false;
        }
        else
        {
            isExists = masterSlaveJedis.exists(key);
            returnResource(masterSlaveJedis);
        }
        
        return isExists;
    }
    
    public boolean exists(String key)
    {
        if( null==key )
        {
            return false;
        }
        
        return exists(key.getBytes());
    }
    
    public Long zadd(String key, double score, String member)
    {
        MasterSlaveJedis masterSlaveJedis = getJedis();
        Long r_l = 0l;
        if (masterSlaveJedis == null)
        {
            r_l = 0l;
        }
        else
        {
            r_l = masterSlaveJedis.zadd(key, score, member);
            returnResource(masterSlaveJedis);
        }

        return r_l;
    }

    public Set<String> zrange(String key, long start, long end)
    {

        Set<String> set = null;
        MasterSlaveJedis masterSlaveJedis = getJedis();
        if (masterSlaveJedis == null)
        {
            set = null;

        }
        else
        {
            set = masterSlaveJedis.zrange(key, start, end);
            returnResource(masterSlaveJedis);
        }

        return set;
    }

    public Double zscore(String key, String member)
    {

        Double d_ = 0d;
        MasterSlaveJedis masterSlaveJedis = getJedis();
        if (masterSlaveJedis == null)
        {
            d_ = 0d;

        }
        else
        {
            d_ = masterSlaveJedis.zscore(key, member);
            returnResource(masterSlaveJedis);
        }

        return d_;
    }
}